package org.jsoupx;

import java.util.HashMap;
import java.util.Map;

import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

public class DocumentX {
	
	/**
	 * 封装 Jsoup Document
	 */
	private Document doc;
	
	/**
	 * 创建连接取得的所有节点
	 */
	private Elements all;
	
	/**
	 * 当前操作节点集合
	 */
	private Elements currentEles;
	
	
	//
	// 构造方法
	//
	
	public DocumentX() {
		this.all();
	}

	public DocumentX(Document doc) {
		this();
		this.doc = doc;
	}
	
	//
	//
	//
	
	/**
	 * 
	 * @param eles
	 */
	public void setCurrentEles(Elements eles) {
		currentEles = eles;
	}
	
	/**
	 * @return 现有节点数
	 */
	public int getEleCount() {
		return this.currentEles.size();
	}

	//
	// 所有已实现方法
	//
	
	/**
	 * 返回当前过虑出的节点
	 * @return
	 */
	public Elements all() {
		if (currentEles != null
				&& currentEles.size() > 0)
			return currentEles;
		
		if (all != null
				&& all.size() > 0)
			return all;
		
		if (doc != null)
			all = doc.getAllElements();
		if (all != null)
			setCurrentEles(all);
		return all;
	}

	/**
	 * 按节点属性过虑
	 * @param propertyName
	 * @param propertyVal
	 * @return
	 */
	public DocumentX byAttr(String propertyName, String propertyVal) {
		Elements eles = new Elements();
		Elements all = this.all();
		for(Element e : all) {
			String val = e.attr(propertyName);
			if (val != null
					&& val.length() > 0
					&& val.equalsIgnoreCase(propertyVal))
				eles.add(e);
		}
		setCurrentEles(eles);
		return this;
	}

	/**
	 * 按节点属性不等于该值过虑
	 * @param propertyName
	 * @param propertyVal
	 * @return
	 */
	public DocumentX byAttrValNot(String propertyName, String propertyVal) {
		Elements eles = new Elements();
		Elements all = this.all();
		for(Element e : all) {
			String val = e.attr(propertyName);
			if (val != null
					|| val.length() < 1
					|| ! val.equalsIgnoreCase(propertyVal))
				eles.add(e);
		}
		
		setCurrentEles(eles);
		return this;
	}

	/**
	 * 按属性值开始特征部分过虑
	 * @param propertyName
	 * @param propertyValStart
	 * @return
	 */
	public DocumentX byAttrValueStarting(String propertyName, String propertyValStart) {
		Elements eles = new Elements();
		Elements all = this.all();
		for(Element e : all) {
			String val = e.attr(propertyName);
			if (val != null
					&& val.length() > 0
					&& val.startsWith(propertyValStart))
				eles.add(e);
		}
		
		setCurrentEles(eles);
		return this;
	}

	/**
	 * 按节点属性结束特征过虑
	 * @param propertyName
	 * @param propertyValEnd
	 * @return
	 */
	public DocumentX byAttrValueEnding(String propertyName, String propertyValEnd) {
		Elements eles = new Elements();
		Elements all = this.all();
		for(Element e : all) {
			String val = e.attr(propertyName);
			if (val != null
					&& val.length() > 0
					&& val.endsWith(propertyValEnd))
				eles.add(e);
		}
		
		setCurrentEles(eles);
		return this;
	}

	/**
	 * 按节点属性包含特征字串过虑
	 * @param propertyName
	 * @param propertyValContain
	 * @return
	 */
	public DocumentX byAttrValueContaining(String propertyName, String propertyValContain) {
		Elements eles = new Elements();
		Elements all = this.all();
		for(Element e : all) {
			String val = e.attr(propertyName);
			if (val != null
					&& val.length() > 0
					&& val.contains(propertyValContain))
				eles.add(e);
		}
		
		setCurrentEles(eles);
		return this;
	}

	/**
	 * 按属性值匹配正则表达式进行过虑
	 * @param string
	 * @param string2
	 * @return
	 */
	public DocumentX byAttrValueMatching(String string, String string2) {
		Elements eles = null;
		setCurrentEles(eles);
		return this;
	}

	/**
	 * 从当前所有节点中过虑出包含特殊代码的节点
	 * @param html
	 * @return
	 */
	public DocumentX containText(String html) {
		Elements eles = new Elements();
		Elements all = this.all();
		for(Element e : all) {
			String htm = e.html();
			if (htm != null
					&& htm.length() > 0
					&& htm.contains(html))
				eles.add(e);
		}
		
		setCurrentEles(eles);
		return this;
	}

	/**
	 * 按标签名过虑当前所有节点
	 * @param tagName
	 * @return
	 */
	public DocumentX byTag(String tagName) {
		Elements eles = new Elements();
		Elements all = this.all();
		for (Element e : all)
			if (e.tagName().equalsIgnoreCase(tagName))
				eles.add(e);
		
		setCurrentEles(eles);
		return this;
	}
	
	
	//
	//
	//
	
	/**
	 * 取子节点作为当前操作节点集合
	 * @param idx  下标( 从 0 起始 )
	 * @return
	 * @throws Exception
	 */
	public DocumentX subEleFetch(int idx) throws Exception {
		if (idx < 0)
			throw new Exception("idx 取值须大于 0");
		Elements all = this.all();
		if (idx > all.size())
			throw new Exception("idx 超出当前节点数上限");
		
		setCurrentEles(all.get(idx).getAllElements());
		return this;
	}
	
	/**
	 * 取子节点作为当前操作节点集合 \n
	 * 默认只取第一个节点的子节点为当前操作节点集
	 * @param tagName
	 * @return
	 */
	public DocumentX subEleFetch() {
		Elements eles = new Elements();
		Elements all = this.all();
		for (Element e : all) {
			setCurrentEles(e.getAllElements());
			break;
		}
		return this;
	}

	/**
	 * 取子节点作为当前操作节点集合
	 * @param tagName
	 * @return
	 */
	public DocumentX subEleFetch(String tagName) {
		this.subEleFetch();
		this.byTag(tagName);
		return this;
	}
	
	
	
	//
	// 其它附加方法
	//
	

	/**
	 * 
	 * @return	您修改后, 整个页面的html 代码
	 */
	public String html() {
		return all.html();
	}
	
	public String text() {
		return all.text();
	}

	/**
	 * 取得tagName 所有标签
	 * @param tagName
	 * @return
	 */
	public Elements getEle(String tagName) {
		Elements eles = new Elements();
		Elements all = this.all();
		for(Element e : all)
			if (e.tagName().equalsIgnoreCase(tagName))
				eles.add(e);
		return eles;
	}
	
	// hash 算法未实现
	/**
	 *  -- 未经过考量， 暂不作修改
	 * @param tagName
	 * @param property
	 * @param baseDir
	 * @return
	 */
	public Map<String, String> replaceAttr(String tagName, String property, String baseDir) {
		Map<String, String> propertyMap = new HashMap<String, String>();
		Elements all = getEle(tagName);
		for(Element e : all) {
			String propertyOld = e.attr(property);
			String propertyNew = hash(propertyOld) + getSuffix(propertyOld);
			// 更新属性
			e.attr(property, baseDir + propertyNew);
			propertyMap.put(propertyOld, propertyNew);
		}
		return propertyMap;
	}

	private String getSuffix(String propertyOld) {
		int idx = propertyOld.lastIndexOf(".");
		if (idx < 0)
			return null;
		String suffix = propertyOld.substring(idx);
		return suffix;
	}
	
	// hash 算法未实现
	private String hash(String propertyOld) {
		return "201314";
	}

}
